package com.pigdogbay.anagramsolver.presenters;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.os.AsyncTask;

import com.pigdogbay.anagramsolver.R;
import com.pigdogbay.anagramsolver.model.IDictionaryModel;
import com.pigdogbay.anagramsolver.model.WordList;
import com.pigdogbay.anagramsolver.model.WordListCallback;
import com.pigdogbay.androidutils.diagnostics.Timing;

public class AnagramPresenter
{
	IDictionaryModel _Model;
	IAnagramView _View;
	WordList _WordList;
	boolean _DictionaryLoaded = false, _Searching = false, _FindSubAnagrams=true;
	boolean _DictionaryLoadThreadLock = false;
	private ArrayList<String> _MatchesArray;
	
	public List<String> getMatchesArray(){
		return _MatchesArray;
	}
	
	public void SetDictionary(List<String> wordList)
	{
		_WordList.SetWordList(wordList);
		_DictionaryLoaded = wordList!=null;
	}
	public void setView(IAnagramView view){
		_View = view;
	}
	public AnagramPresenter(IDictionaryModel model)
	{
		_WordList = new WordList();
        _MatchesArray = new ArrayList<String>();
		_Model = model;
		
	}

	public void Clear()
	{
		_MatchesArray.clear();
		_View.updateList();
		_View.setStatus("",false);
		_View.setQuery("");
		_View.setError(null);
		_View.showKeyboard();
	}
	private boolean IsQueryOK(String query)
	{
		if (isNullOrBlank(query))
		{
			_View.setError(_View.getStringResource(R.string.search_entry_error_message));
			return false;
		}
		if (!_DictionaryLoaded)
		{
			_View.setError(_View.getStringResource(R.string.search_dictionary_not_loaded));
			return false;
		}
		_View.setError(null);
		return true;
	}

	public void Search()
	{
		if (_Searching)
		{
			return;
		}
		String query = _View.getQuery();
		query = _WordList.ConvertQuery(query);
		if (!IsQueryOK(query))
		{
			return;
		}
		_MatchesArray.clear();
		_View.updateList();
		_Searching = true;
		_View.setStatus(_View.getStringResource(R.string.search_searching),true);
		this.new BackgroundWorker().execute(query);
	}

	private static boolean isNullOrBlank(String param)
	{
		return param == null || param.trim().length() == 0;
	}

	public String getWordURL(int pos)
	{
		String word = _MatchesArray.get(pos);
		//Removes formatting such as missing letters
		int index = word.indexOf(" (");
		word =  index==-1 ? word : word.substring(0,index);
		String url = _View.getStringResource(R.string.DictionaryURLTemplate);
	    return url.replace("$WORD", word);
	}

	private class BackgroundWorker extends AsyncTask<String, String, Void> implements WordListCallback
	{
		int numOfMatches = 0;
		
		@Override
		protected Void doInBackground(String... params)
		{
			Timing timing = new Timing();
			try
			{
				String query = params[0];
				numOfMatches = 0;
				_WordList.RunQuery(query,BackgroundWorker.this);
				if (	_FindSubAnagrams 
						&& !query.contains(" ")
						&& !query.contains("#")
						&& !_WordList.IsPartialWord(query) 
						&& query.length() > 2
						&& query.length() < 20)
				{
					_WordList.FindSubAnagrams(query, BackgroundWorker.this);
				}
			} catch (Exception e)
			{
			}
			timing.LogDuration("CleverDic");
			return null;
		}
		@Override
		protected void onProgressUpdate(String... values)
		{
			_MatchesArray.add(values[0]);
			_View.updateList();
		}

		@Override
		protected void onPostExecute(Void result)
		{
			_View.setStatus(_View.getStringResource(R.string.search_matches_found)+Integer.valueOf(numOfMatches).toString(),false);
			_Searching = false;
		}
		@Override
		public void Update(String result)
		{
			numOfMatches++;
			publishProgress(result);
			
		}
	}
	public void setUpDictionary()
	{
		if (_Model.getDictionary()==null)
		{
			runDictionaryBackgroundWorker();
		}
		else
		{
			SetDictionary(_Model.getDictionary());
			_View.showReady();
		}
	}
	
	synchronized private void runDictionaryBackgroundWorker()
	{
		if (!_DictionaryLoadThreadLock) {
			new LoadDictionaryWorker().execute();
			_DictionaryLoadThreadLock = true;
		}		
	}

	private List<String> loadDictionary() throws IOException
	{
		List<String> standard = _Model.loadStandardDictionary();
		return standard;
	}
	
	/*
	 * Dictionary takes around 1000ms/2300ms to load on Nexus 7,
	 * 2600ms/8000ms on ACE phone. (Measured on 11 Sept 2013 with prior GC)
	 * Need to load this on a worker thread in the background to
	 * avoid the application freezing when starting up.
	 */
	private class LoadDictionaryWorker extends AsyncTask<Void, Void, Void> {
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			_View.showLoadingDictionary();
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			_DictionaryLoadThreadLock = false;
			_View.showReady();
		}

		@Override
		protected Void doInBackground(Void... params) {
			//Memory intensive operation, causes HTC to crash if dictionary is reloaded
			//Running gc before adds 200-300 milliseconds on the load time (nexus 7)
			//but saves 1300 - 1500 milliseconds on the Ace
			_Model.setDictionary(null);
			SetDictionary(null);
			System.gc();
			try {
				List<String> dictionary = loadDictionary();
				_Model.setDictionary(dictionary);
				SetDictionary(dictionary);
			}
			catch (Exception e) {
				_View.showLoadingDictionaryError();
			}
			return null;
		}
	}
	
	public String getResults()
	{
		StringBuilder sbuff = new StringBuilder();
		sbuff.append("-Anagram Solver-\n\nQuery:\n");
		sbuff.append(_View.getQuery());
		sbuff.append("\n\nMatches:\n");
		for (String result : _MatchesArray) {
			sbuff.append(result);
			sbuff.append('\n');
		}
		sbuff.append('\n');
		sbuff.append(_View.getStringResource(R.string.website));
		return sbuff.toString();
	}
}
